#include <stdio.h>
#include <stdlib.h>
#include "double_list.h"

#if defined(_DOUBLE_LIST_VER3_)
struct d_node
{
    struct d_node *prev;
    struct d_node *next;
    void *data;
};

_DNode *create_node(void *data)
{
    _DNode *new_node = NULL;

    new_node = (_DNode *)malloc(sizeof(_DNode));
    if (new_node == NULL)
    {
	return NULL;
    }

    new_node->prev = NULL;
    new_node->next = NULL;
    new_node->data = data;

    return new_node;
}

DListRet destory_node(_DNode *node)
{
    if (NULL == node)
    {
	return DListRetFail;
    }

    if (node->data != NULL)
    {
	free(node->data);	/*How can we know the memory on heap or stack?*/
    }
    free(node);	/*How to deal with the user data ?*/

    return DListRetOk;
}

_DList create_list(void)
{
    _DList new_list = NULL;
    
    new_list = (_DList)malloc(sizeof(*new_list));
    if (NULL == new_list)
    {
	return NULL;
    }

    new_list->prev = NULL;
    new_list->next = NULL;
    new_list->data = NULL;

    return new_list;
}

DListRet destroy_list(_DList head)
{
    _DNode *del = NULL;
    _DNode *tmp = NULL;

    if (NULL == head)
    {
	return DListRetFail;
    }

    for(del = head->next; del != NULL; del = head->next)
    {
	head->next = del->next;

	if (del->data != NULL)
	{
	    free(del->data);
	}
	free(del);
    }
    
    return DListRetOk;
}

DListRet is_existed(_DList head, DListCmpFunc cmp, void *data)
{
    _DNode *tmp = NULL;

    if ((head == NULL) || (data == NULL))
    {
	return DListRetFail;
    }

    for (tmp = head->next; tmp != NULL; tmp = tmp->next)
    {
	if (0 == cmp(tmp->data, data))
	{
	    return DLIST_ENTRY_EXISTED;
	}
	continue;
    }

    return DLIST_ENTRY_NOT_EXIST;
}

DListRet insert_to_list(_DList head, _DNode *node)
{
    if ((NULL == head) || (NULL == node))
    {
	return DListRetFail;
    }

    if (NULL == head->next)
    {
	head->next = node;
	node->prev = head;
    }
    else
    {
	node->next = head->next;
	head->next->prev = node;
	node->prev = head;
	head->next = node;
    }

    return DListRetOk;
}

DListRet delete_node(_DList head, DListCmpFunc cmp, void *key)	/*This is not completely right*/
{
    _DNode *del = NULL;
    _DNode *tmp = NULL;

    if (NULL == head)
    {
	return DListRetFail;
    }

    for (del = head->next; del != NULL; del = del->next)
    {
	if (0 == cmp(del->data, key))
	{
	    tmp = del->prev;
	    if (NULL != del->next)
	    {
		del->prev->next = del->next;
		del->next->prev = del->prev;
		free(del);
		del = tmp;
		continue;
	    }
	    else
	    {
		del->prev->next = NULL;
		free(del);
		break;
	    }
	}
    }
    return DListRetOk;
}

DListRet dlist_print(_DList thiz, DListPrintFunc print)
{
    DListRet ret = DListRetOk;
    _DNode *iter = thiz->next;

    while(iter != NULL)
    {
	print(iter->data);
	iter = iter->next;
    }

    return ret;
}

DListRet dlist_foreach(_DList thiz, DListVisitFunc visit, void *arg)
{
    DListRet ret = DListRetOk;
    _DNode *iter = thiz->next;

    while(iter != NULL && ret != DListRetFail)
    {
	ret = visit(arg, iter->data);
	iter = iter->next;
    }

    return ret;
}

#endif
